'''
A thread that downloads whatever hides behind an URL to a specified file.

Licensed under the GPL.

@author: screwdriver
'''

'''
Version history:
----------------
2009-03-21 screwdirver Created (Adapted from a sample I got in my opertion-system course - Thanks go to Mr. Georg Esser.).
2009-03-21 screwdirver Implemented error handling.
2009-03-23 screwdirver Released version 1.0.0 
---
2009-03-27 screwdriver Put debug macro into it's own module.
'''

import urllib;
import random;
import time;

from debug import debug;

from threading import Thread;
from string import Template;
from mimetools import Message;

WRONG_MIME_TYPE = "\"$file\" is no zip file, mime-type: \"$mimeType\"";
IO_ERROR = "URL $url could not be retrieved, due to error: $error";
STOPPED = "Downlaod Stopped.";
GIVING_UP = "Retries depleted, giving up.";

'''
how many times to retry downloading
'''
_MAX_RETRY = 10;


class Downlaoder(Thread):
	'''
	downloads an arbitrary web resource to a specified local file
	'''
	
	def sucessfull(): #@NoSelf
		doc = """Indicates, if the instance was sucessful.""" #@UnusedVariable
		
		def fget(self):
			return self._sucessfull
			
		def fset(self, value):
			self._sucessfull = value
			
		def fdel(self):
			del self._sucessfull
			
		return locals()
		
	sucessfull = property(**sucessfull())
	
	def lasterror(): #@NoSelf
		doc = """Human readable reason for the failure.""" #@UnusedVariable
		
		def fget(self):
			return self._lasterror
			
		def fset(self, value):
			self._lasterror = value
			
		def fdel(self):
			del self._lasterror
			
		return locals()
		
	lasterror = property(**lasterror())
	
	def stopped(): #@NoSelf
		doc = """Stop the download and indicate if the download has been stopped.""" #@UnusedVariable
		
		def fget(self):
			return self._stopped
			
		def fset(self, value):
			self._stopped = value
			
		def fdel(self):
			del self._stopped
			
		return locals()
		
	stopped = property(**stopped())
	
	def __init__(self, url, savePath):
		Thread.__init__(self);
		self.url = url;
		self.savePath = savePath;
		self.stopped = False;
		self.sucessfull = False;
		self.lasterror = None;
	
	def run(self):
		debug (["downloading", self.url, "..."]);
		
		for i in range(1, _MAX_RETRY):
			
			if not self.stopped : 
				try:
					(filename, headers) = urllib.urlretrieve(self.url, self.savePath);
					mimeType = headers.gettype();
					if (mimeType == "application/zip"):
						self.sucessfull = True;
						return;
					else :
						self.lasterror = Template(WRONG_MIME_TYPE).safe_substitute(mimeType = mimeType, file = self.savePath);
						debug (self.lasterror);
						
				except IOError, e:
					self.lasterror = Template(IO_ERROR).safe_substitute(url = self.url, error = repr(e));
					debug (self.lasterror);
				
				randomTime = random.randint(1,10);
				debug (Template("Download of $url failed $failures of $maxFailures times, next try in $delay seconds.").safe_substitute(url = self.url, failures = i, maxFailures = _MAX_RETRY, delay = randomTime));
				time.sleep(randomTime);
			else :
				self.lasterror = STOPPED;
				return
		
		self.lasterror = GIVING_UP;
		
	def stop(self):
		self.stopped = True;
